package com.jswdwsx.esign.service

import com.jswdwsx.esign.cloud.exception.EsignException
import com.jswdwsx.esign.commom.ResEnum
import com.jswdwsx.esign.entity.FileTemplatePO
import com.jswdwsx.esign.exception.EsignBusinessException
import com.jswdwsx.esign.protocol.EsignApi
import com.jswdwsx.esign.protocol.EsignOtherApi
import com.jswdwsx.esign.protocol.request.AddComponentsReq
import com.jswdwsx.esign.protocol.request.CreateFileTemplateReq
import com.jswdwsx.esign.protocol.response.CreateTemplateResp
import com.jswdwsx.esign.protocol.response.QueryFileTemplateResp
import com.jswdwsx.esign.repo.FileTemplateRepository
import com.jswdwsx.esign.util.md5File
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody
import okio.BufferedSink
import okio.source
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import org.springframework.web.multipart.MultipartFile

@Service
class FileTemplateService(
    private val esignApi: EsignApi,
    private val esignOtherApi: EsignOtherApi,
    private val fileTemplateRepository: FileTemplateRepository
) {
    private val logger = LoggerFactory.getLogger(FileTemplateService::class.java)

    fun queryTemplate(fileTemplateId: String): QueryFileTemplateResp {

        logger.info("查询模板请求参数：${fileTemplateId}")
        val esignResp = esignApi.queryTemplate(fileTemplateId)
        logger.info("查询模板请求响应:${esignResp}")

        return esignResp.data(ResEnum.CallEsignQueryTemplateFail)
    }

    fun createFileTemplate(flowTemplateId: String, templateName: String, file: MultipartFile) {
        val fileName = file.originalFilename ?: throw EsignBusinessException(ResEnum.ParamErr)
        if (!fileName.endsWith(".pdf")) throw EsignBusinessException(ResEnum.FileMustPdf)
        val fileMd5 = md5File(file).also { println(it) }
        val createTemplateResp = createTemplate(fileName, templateName, fileMd5)

        uploadFileByRetrofit(file, fileMd5, createTemplateResp.uploadUrl)
        fileTemplateRepository.save(
            FileTemplatePO(
                fileTemplateId = createTemplateResp.templateId,
                flowTemplateId = flowTemplateId,
                name = templateName
            )
        )
    }

    private fun createTemplate(fileName: String, templateName: String, fileMd5: String): CreateTemplateResp {

        // 这边fileName参数必须加".pdf"后缀，不然会有诡异问题，导致后续模板参数无法填充，鬼知道E签宝里面发生了什么
        val req = CreateFileTemplateReq(
            contentMd5 = fileMd5,
            contentType = "application/octet-stream",
            fileName = "$templateName.pdf",
            convert2Pdf = (if (fileName.endsWith("pdf")) "false" else "true")
        )
        logger.info("创建模板请求参数：${req}")
        val esignResp = esignApi.createTemplate(req)
        logger.info("创建模板响应参数：${esignResp}")
        return esignResp.data(ResEnum.CallEsignCreateTemplateFail)
    }

    fun addComponent(templateId: String, addComponentsReq: AddComponentsReq): Boolean {
        val esignResp = esignApi.addComponents2Template(templateId, addComponentsReq)
        return esignResp.isSuccess
    }

    /**
     * 向E签宝指定地址上传模板文件
     * 使用retrofit方式
     */
    fun uploadFileByRetrofit(file: MultipartFile, fileMd5: String, uploadUrl: String) {
        val mediaType = DEFAULT_MIME.toMediaTypeOrNull()
        val requestBody = object : RequestBody() {
            override fun contentType() = mediaType
            override fun writeTo(sink: BufferedSink) {
                file.inputStream.source().use {
                    sink.writeAll(it)
                }
            }
        }

        val call = esignOtherApi.uploadFile(uploadUrl, DEFAULT_MIME, fileMd5, file.size.toString(), requestBody)
        val response = call.execute()
        logger.info("文件上传：响应结果：${response.body().toString()}")
        if (!response.isSuccessful) {
            throw EsignException("创建模板上传文件失败： $response")
        }
    }

    companion object {
        private const val DEFAULT_MIME = "application/octet-stream"
    }
}